The doFilter() method of PageFilter sets the boolean variable FILTER_APPLIED on the request to true, before executing. When an exception occurs in the call to chain.doFilter(), the execution stops. After the servlet invokes the error page, the PageFilter is invoked again, but stops when it sees that the FILTER_APPLIED attribute is already set to true.

The solution is to extend the PageFilter, catch all exceptions and set the FILTER_APPLIED variable to null. Then use this filter in the web.xml.

public class ErrorHandlingSiteMeshPageFilter extends PageFilter {
 
    public void doFilter(ServletRequest request, ServletResponse rs, FilterChain chain) throws IOException, ServletException {
        try {
            super.doFilter(request, rs, chain);
        } catch (RuntimeException e) {
            clearFilteredVariable(request);
            throw e;
        } catch(IOException e) {
            clearFilteredVariable(request);
            throw e;
        } catch(ServletException e) {
            clearFilteredVariable(request);
            throw e;
        }            
    }
    
    private void clearFilteredVariable(ServletRequest request) {
        request.setAttribute(FILTER_APPLIED, null);
    }
}

For more information of related discussion, see here

Sollution contributed by Hendrikd. Thx Hendrikd.